iT邦幫忙

2022 iThome 鐵人賽

DAY 12
0
Modern Web

前端技術研究系列 第 12

Redux Toolkit 基礎應用

  • 分享至 

  • xImage
  •  

前言:

只有看這些名詞解釋是不是霧煞煞,現在就由我來導覽一下他們在程式碼上的實際應用吧。
大家可配合官網上的code 來解讀,或是透過 codeSandBox 一同服用。
官網網址:https://redux-toolkit.js.org/tutorials/typescript

開始囉

1.在 store.ts 做一些基礎設定,透過 configureStore() 建立 Redux Store。configureStore 裡面可以設定很多擴充套件,比如 Redux-Saga 他是一個 middlerware 就可以直接引入 RTK 裡一同使用。

// app/store.ts

import { configureStore, ThunkAction, Action } from "@reduxjs/toolkit";
import counterReducer from "../features/counter/counterSlice";
// ? configureStore 是優化redux createStore的寫法,可以接收 reducer 後建立 store,代入已經在slice產生好的reducer
// 透過 configureStore() 建立 Redux Store
export const store = configureStore({
  reducer: {
    counter: counterReducer
  }
});

export type AppDispatch = typeof store.dispatch;
export type RootState = ReturnType<typeof store.getState>;
//  在這邊先行定義 redux-thunk type
export type AppThunk<ReturnType = void> = ThunkAction<
  ReturnType,
  RootState,
  unknown,
  Action<string>
>;

2.引入 store.ts ,被包裹在 Provider 底下的都可以去操作 store 的 state

// index.tsx
import { Provider } from "react-redux";
import { store } from "./app/store";
// ... 省略
    <Provider store={store}>
      <App />
    </Provider>

3.Counter.tsx 是範例中主要讀取資料以及控制 state 的元件,useAppSelector 可拿取資料, useAppDispatch 可以操作資料,他們兩者都在hook.ts 中被定義。每一個按鈕都會去 dispatch 對應 action。

// Counter.tsx
import { useAppSelector, useAppDispatch } from "../../app/hook";

// ... 這裡省略非常多
    <button
          className={styles.button}
          onClick={() => dispatch(incrementByAmount(incrementValue))}
        >
          Add Amount
        </button>

4.counterSlice.ts 是設定 slice redurcer 的檔案

// counterSlice.ts
import { createAsyncThunk, createSlice, PayloadAction } from "@reduxjs/toolkit";

// ... 這裡省略一些設定
// createAsyncThunk 在此先行設定 
export const incrementAsync = createAsyncThunk(...); 

// 建立好的 slice 可以產生 reducer 和 action creators 供後續使用
export const counterSlice = createSlice({
  name: "counter",
  initialState,
  // counterSlice 中,其 state 的型別會被 initialState 的型別所決定

  reducers: {
    increment: (state) => {
      state.value += 1;
    },
    decrement: (state) => {
      state.value -= 1;
    },

    // action.payload 是接受元件中傳入的 data 來做後續操作
    incrementByAmount: (state, action: PayloadAction<number>) => {
      state.value += action.payload;
    }
  },
  // extraReducers 區塊是來操作上方宣告的 createAsyncThunk function
  extraReducers: (builder) => {
    builder
      .addCase(incrementAsync.pending, (state) => {
        state.status = "loading";
      })
      .addCase(incrementAsync.fulfilled, (state, action) => {
        state.status = "idle";
        state.value += action.payload;
      })
      .addCase(incrementAsync.rejected, (state) => {
        state.status = "failed";
      });
  }
});

export const { increment, decrement, incrementByAmount } = counterSlice.actions;
// 在此設定元件中可取用的 state
export const countState = (state: RootState) => state.counter;

// 這邊是介紹 redux-thunk 寫法
export const incrementIfOdd = (amount: number): AppThunk => (
  dispatch,
  getState
) => {
  const currentValue = countState(getState());
  if (currentValue.value % 2 === 1) {
    dispatch(incrementByAmount(amount));
  }
};

export default counterSlice.reducer;

createAsyncThunk 有三種狀態(pending/fulfilled/rejected)可用來表示非同步請求的生命週期,這可以讓我們的程式碼有一些更彈性的設定,比如我在 codeSandBox 增加的 loading 顯示,或是我們的操作執行過程中failed 的話也能有一些更彈性的設定。
還有最後面有稍微帶到的 redux-thunk ,他其實是 function 內包裹 function 寫法,不過我這邊先單純加個判斷式意思意思一下。

結語:
技術更新日新月異,寫法真的也是越來越平易近人了,接下來還有 redux-sage的出現,基本取代了redux-thunk的功能,前幾天跟同事聊到已經用習慣 redux-saga 連 thunk 是啥都不知道了,雖然我在看 RTK 官方文件前也不知道/images/emoticon/emoticon16.gif


上一篇
Redux Toolkit 入門課
下一篇
react 生命週期 上集
系列文
前端技術研究30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言